<template>
  <el-row class="editor-layout">
    <!-- 左侧：文件管理 -->
    <el-col :span="3" class="list-container">
      <div class="file-manager-header">
        <span class="file-manager-title">文件管理</span>
        <el-button
            class="btn-new-file-icon"
            type="text"
            icon="el-icon-plus"
            @click="createNewFile()"
            title="新建空文件"
        ></el-button>
      </div>
      <div class="file-list">
        <div
            v-for="(file, index) in fileList"
            :key="index"
            class="file-item"
            :class="{ active: selectedFileIndex === index }"
            @click="selectFile(index)"
        >
         <span>
           {{ file.label }}
         </span>
          <span>
            <el-button
                v-if="selectedFileIndex === index"
                type="text"
                size="mini"
                icon="el-icon-check"
                @click.stop="saveCurrentFile"
                style="margin-left: 8px; color: #1890ff;"
                title="保存文件"
            ></el-button>
          <el-button
              v-if="selectedFileIndex === index"
              type="text"
              size="mini"
              icon="el-icon-close"
              @click.stop="deleteCurrentFile"
              style="margin-left: 8px; color: red;"
              title="删除文件"
          ></el-button>
          </span>

        </div>
      </div>
    </el-col>
    <!-- 中间：编辑器 -->
    <el-col :span="13" class="editor-container">
      <!-- 编辑器 Header -->
      <div class="editor-header">
        <span class="editor-title">
          {{ selectedFileIndex !== null ? fileList[selectedFileIndex]?.label || '未命名文件' : '请选择文件' }}
        </span>
<!--            <el-button-->
<!--                v-if="selectedFileIndex !== null"-->
<!--                size="mini"-->
<!--                type="primary"-->
<!--                icon="el-icon-document-checked"-->
<!--                @click="saveCurrentFile"-->
<!--                style="margin-left: 8px;"-->
<!--            >-->
<!--              保存-->
<!--            </el-button>-->
      </div>
      <div ref="monacoContainer" class="monaco-editor-container"></div>
    </el-col>
    <!-- 右侧：Copilot 聊天 -->
    <el-col :span="8" class="chat-container">
      <div class="chat-wrapper">

        <div class="chat-header">
          <h3 style="margin: 0;display: flex;justify-content: space-between;align-items: center">
            <span>数据治理助手</span>
            <el-button style="padding: 10px;" icon="el-icon-refresh" @click="clearChat"></el-button>
          </h3>
        </div>

        <!-- 消息列表 -->
        <div class="chat-messages" ref="messagesContainer">
          <div
              v-for="(msg, index) in chatMessages"
              :key="index"
              :class="['message', msg.role]"
          >
            <div class="message-avatar">
              <el-avatar
                  :style="{'background-color': msg.role === 'user' ? '#155eef' : 'slategray'}"
                  :icon="msg.role === 'user' ? 'el-icon-user' : 'el-icon-chat-round'"></el-avatar>
            </div>
            <div class="message-content">
              <div class="message-text" v-html="formatMessage(msg.content)"></div>
              <div class="message-time">{{ formatTime(msg.timestamp) }}</div>
            </div>
          </div>

          <!-- 流式输入动画 -->
          <div v-if="isStreaming" class="message assistant">
            <div class="message-avatar" style="width: 40px;height: 40px;">
              <!--              <el-avatar icon="el-icon-chat-round"></el-avatar>-->
            </div>
            <div class="message-content">
              <div class="typing-indicator">
                <span></span><span></span><span></span>
              </div>
            </div>
          </div>
        </div>

        <!-- 快捷按钮 -->
        <div class="quick-actions">
          <el-button
              v-for="action in quickActions"
              :key="action.label"
              size="mini"
              :class="{ 'is-selected': action.selected }"
              @click="executeQuickAction(action)"
          >
            {{ action.label }}
          </el-button>
        </div>

        <!-- 上传文件按钮 -->
        <div class="file-upload-container" style="padding: 8px 0;">
          <el-upload
              :multiple="true"
              :auto-upload="true"
              :show-file-list="false"
              action=""
              accept=".sql,.js,.ts,.json,.txt,.csv"
              :http-request="handleFileUpload"
          >
            <el-button size="mini" type="primary" icon="el-icon-upload">上传文件</el-button>
          </el-upload>
          <!-- 已上传文件列表（可选） -->
          <!-- 已上传文件列表（支持删除） -->
          <div v-if="uploadedFiles.length > 0" class="uploaded-files"
               style="margin-top: 6px; font-size: 12px; color: #666;">
            <div
                v-for="(file, idx) in uploadedFiles"
                :key="idx"
                style="display: flex; justify-content: space-between; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding: 2px 0;"
            >
              <span style="flex: 1;">📄 {{ file.name }} ({{ (file.size / 1024).toFixed(1) }}KB)</span>
              <el-button
                  size="mini"
                  type="danger"
                  icon="el-icon-delete"
                  circle
                  @click="removeUploadedFile(idx)"
                  style="margin-left: 4px; padding: 4px;"
                  title="删除文件"
              ></el-button>
            </div>
          </div>
        </div>

        <!-- 输入框 -->
        <div class="chat-input-container">
          <el-input
              type="textarea"
              :rows="2"
              placeholder="向数据治理助手提问，按回车输入"
              v-model="userInput"
              @keyup.enter.native="handleSendMessage"
              ref="chatInput"
          >
            <template #append>
              <el-button
                  icon="el-icon-position"
                  @click="handleSendMessage"
                  :loading="isStreaming"
              ></el-button>
            </template>
          </el-input>
        </div>

        <!-- 操作按钮 -->
        <div class="dialog-footer">

          <!--          <el-button size="small" @click="clearChat">清空对话</el-button>-->
          <!--          <el-button size="small" type="primary" @click="insertToEditor">插入代码</el-button>-->
          <el-button size="small" type="primary" @click="handleSendMessage">发送</el-button>

        </div>
      </div>
    </el-col>
  </el-row>
</template>

<script>
import * as monaco from 'monaco-editor';
import request from '@/utils/request'
import hljs from 'highlight.js/lib/core'
import {marked} from 'marked'
import sql from 'highlight.js/lib/languages/sql'
// ✅ 正确路径（注意：release/esm）
import * as sqlcode from 'monaco-languages/release/esm/sql/sql.js';

export default {
  name: 'MonacoEditor',

  props: {
    value: {
      type: String,
      default: ''
    },
    language: {
      type: String,
      default: 'javascript'
    },
    theme: {
      type: String,
      default: 'vs-dark'
    },
    readOnly: {
      type: Boolean,
      default: false
    }
  },

  data() {
    return {
      editor: null,
      FIXED_QA: new Map([]),
      uploadedFiles: [], // 存储已上传的文件信息 { name, size, content }
      monaco: null,// Copilot 对话框相关数据
      copilotVisible: false, // 控制对话框显示/隐藏
      isExecutingSQL: false, // 控制对话框显示/隐藏
      userQuestion: '', // 用户输入的问题
      suggestions: [],// 存储助手返回的建议
      userInput: '',
      fileList: [
        {label: '主程序.sql', content: 'function main() {\n  console.log("Hello World");\n}\nmain();'},
        {
          label: '工具函数.sql',
          content: 'function add(a, b) {\n  return a + b;\n}\n\nfunction multiply(a, b) {\n  return a * b;\n}'
        },
        {
          label: '初始化.sql',
          content: 'CREATE TABLE users (\n  id INT PRIMARY KEY,\n  name VARCHAR(100)\n);\n\nINSERT INTO users (id, name) VALUES (1, \'Alice\');'
        },
      ],
      selectedFileIndex: 0, // 默认选中第一个
      chatMessages: [],
      isStreaming: false,
      quickActions: [
        {
          label: '通用',
          action: 'explain',
          selected: false,
          prompt: '生成代码注释：为当前选中的代码逐行添加简洁的注释。只返回注释后的完整代码，不要任何解释文字。'
        },
        {
          label: '知识问答',
          action: 'fix',
          selected: false,
          prompt: '修复当前选中代码中的错误。只返回修复后的完整代码，不要说明修复了哪里。'
        },
        {
          label: '數据探索',
          action: 'optimize',
          selected: false,
          prompt: '优化当前选中的代码。只返回优化后的完整代码，不要解释优化内容。'
        },
        {
          label: '數据核查',
          action: 'comment',
          selected: false,
          prompt: '为当前选中的代码添加必要的注释。只返回注释后的完整代码，不要额外说明。'
        }
      ],
      copilotTimer: null
    };
  },

  created() {
    var that = this
    request.get('/code-files').then(res => {
      console.log('res.data', res.data)
      that.fileList = res.data.data;
      const initialFile = that.fileList[this.selectedFileIndex];
      if (initialFile) {
        that.editor.setValue(initialFile.content);
        monaco.editor.setModelLanguage(this.editor.getModel(), this.guessLanguage(initialFile.label));
      }
    })
    request.get('/qa').then(res => {
      if (res.data && Array.isArray(res.data.data)) {
        // 后端返回的就是 { id, question, answer }，直接使用
        console.log('res.data.data', res.data.data);
        // this.qaList = res.data.data;
        const transformedData = res.data.data
            .map(item => [item.question, item.answer]);
        that.FIXED_QA = new Map(transformedData)

      }
    }).catch(err => {
      console.error('加载问答数据失败:', err);
      this.$message.error('加载失败，使用默认问答');
    });
    // 检查 hljs 是否加载
    console.log('this.FIXED_QA', this.FIXED_QA)
    hljs.registerLanguage('sql', sql)
  },

  mounted() {
    this.quickActions[0].selected = true;
    this.$nextTick(() => {
      this.initMonaco();
    });
  },

  beforeDestroy() {
    if (this.editor) {
      this.editor.dispose();
    }
  },

  methods: {
    highlightCodeBlocks() {
      const container = this.$refs.messagesContainer;
      if (!container) return;

      // 获取所有未被包装的 <pre> 元素
      const pres = Array.from(container.querySelectorAll('pre'));
      for (const pre of pres) {
        // 跳过已处理的代码块
        if (pre.parentElement?.classList.contains('code-container')) continue;

        const code = pre.querySelector('code');
        if (!code) continue;

        const parent = pre.parentNode;
        if (!parent) continue;

        // 保存原位置（用于插入 wrapper）
        const nextSibling = pre.nextSibling;

        // 提取语言
        const langMatch = code.className.match(/language-(\w+)/);
        const lang = langMatch ? langMatch[1] : 'text';

        // 创建 wrapper 容器
        const wrapper = document.createElement('div');
        wrapper.className = 'code-container';
        wrapper.style.cssText = `
      margin: 10px 0;
      border-radius: 6px;
      overflow: hidden;
      background: #f8f9fa;
      font-size: 13px;
      box-shadow: 0 1px 2px rgba(0,0,0,0.05);
    `;

        // 创建 header
        const header = document.createElement('div');
        header.className = 'code-header';
        header.style.cssText = `
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 4px 10px;
      background: #e9ecef;
      font-size: 12px;
      color: #495057;
      user-select: none;
    `;

        const langLabel = document.createElement('span');
        langLabel.innerText = lang.toUpperCase();

        // 按钮组
        const buttonGroup = document.createElement('div');
        buttonGroup.style.cssText = 'display: flex; gap: 6px;';

        // === 复制按钮 ===
        const copyButton = document.createElement('button');
        copyButton.className = 'copy-btn';
        copyButton.innerText = '运行';
        copyButton.style.cssText = `
      padding: 2px 8px;
      background: #67c23a;
      color: white;
      border: none;
      border-radius: 3px;
      cursor: pointer;
      font-size: 12px;
    `;
        copyButton.addEventListener('click', async () => {
          // try {
          //   await navigator.clipboard.writeText(code.innerText);
          //   const original = copyButton.innerText;
          //   copyButton.innerText = '已复制';
          //   copyButton.style.background = '#28a745';
          //   setTimeout(() => {
          //     copyButton.innerText = original;
          //     copyButton.style.background = '#6c757d';
          //   }, 1500);
          // } catch (err) {
          //   console.error('复制失败:', err);
          //   copyButton.innerText = '失败';
          //   copyButton.style.background = '#dc3545';
          //   setTimeout(() => {
          //     copyButton.innerText = '复制';
          //     copyButton.style.background = '#6c757d';
          //   }, 1500);
          // }
          this.executeSQL(code.innerText);
        });

        // === 插入按钮 ===
        const insertButton = document.createElement('button');
        insertButton.className = 'insert-btn';
        insertButton.innerText = '插入';
        insertButton.style.cssText = `
      padding: 2px 8px;
      background: #155eef;
      color: white;
      border: none;
      border-radius: 3px;
      cursor: pointer;
      font-size: 12px;
    `;
        insertButton.addEventListener('click', () => {
          this.insertToEditor(code.innerText);
        });

        // 组装 header
        buttonGroup.appendChild(copyButton);
        buttonGroup.appendChild(insertButton);
        header.appendChild(langLabel);
        header.appendChild(buttonGroup);
        wrapper.appendChild(header);
        wrapper.appendChild(pre); // 移动 pre 到 wrapper 内

        // 插入 wrapper 到原位置
        if (nextSibling) {
          parent.insertBefore(wrapper, nextSibling);
        } else {
          parent.appendChild(wrapper);
        }

        // 执行语法高亮（如果尚未高亮）
        if (!code.classList.contains('hljs')) {
          code.className = `hljs language-${lang}`;
          if (typeof hljs !== 'undefined') {
            hljs.highlightElement(code);
          }
        }
      }
    },
    // 格式化消息内容（支持简单的Markdown样式）
    formatMessage(content) {
      if (!content) return ''
      // console.log('原始 content:', JSON.stringify(content))

      try {
        return marked.parse(content, {
          breaks: true,
          gfm: true
        })
      } catch (err) {
        console.error('Markdown 高亮解析失败:', err)
        return content
      }
    },

    async streamChatResponse(message, codeContext) {
      this.isStreaming = true;
      this.chatMessages.push({
        role: 'user',
        content: message,
        timestamp: new Date()
      });
      console.log('this.uploadedFiles', this.uploadedFiles);

      const normalizedMessage = message.trim().toLowerCase();
      if (this.FIXED_QA.has(normalizedMessage)) {
        const fullAnswer = this.FIXED_QA.get(normalizedMessage);

        // 添加助手占位消息
        this.chatMessages.push({
          role: 'assistant',
          content: '',
          timestamp: new Date()
        });
        const assistantIndex = this.chatMessages.length - 1;
        const thinkDelay = Math.floor(Math.random() * 401) + 600;
        // 模拟“思考”时间，比如 800ms
        setTimeout(() => {
          let i = 0;
          const interval = setInterval(() => {
            if (i < fullAnswer.length) {
              this.chatMessages[assistantIndex].content += fullAnswer[i];
              i++;
              this.$forceUpdate();
              this.$nextTick(() => {
                this.scrollToBottom();
                this.highlightCodeBlocks();
              });
            } else {
              clearInterval(interval);
              this.isStreaming = false;
            }
          }, Math.floor(Math.random() * 41) + 30); // 每 20ms 输出一个字符
        }, thinkDelay); // ← 思考延迟时间（可调整）

        return;
      }

      // // 添加助手消息占位符用于流式更新
      this.chatMessages.push({
        role: 'assistant',
        content: '',
        timestamp: new Date()
      });

      try {
        const response = await fetch('https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions', {
          method: 'POST',
          headers: {
            'Authorization': 'Bearer sk-a731f551ecd34cdbb06487f7464ff978', // 请替换为您的API密钥
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            model: 'qwen-plus',
            messages: [
              // 关键：使用system角色设定严格的全局规则
              {
                role: 'system',
                content: `你是一个专业的SQL代码生成助手。请严格遵守以下规则：
1. 你的所有回复必须是完整的SQL语句，且必须是可直接执行的SQL代码。
2. 禁止在代码中添加任何形式的注释、解释性文字。
3. 如果用户的问题无法用SQL解决，请直接返回"无法生成代码"。
4. 生成的SQL应符合标准语法规范，包含所有必要的部分（如SELECT、FROM、WHERE等），确保可以直接在数据库中运行。
5. 加入Markdown代码块标记。
`,
//                 content: `你是一个专业的代码生成助手。请严格遵守以下规则：
// 1. 你的所有回复必须是纯代码，且必须是**完整、可运行**的代码段。
// 2. 禁止在代码中添加任何形式的注释、解释性文字、Markdown代码块标记（如\`\`\`python）。
// 3. 如果用户的问题无法用代码解决，请直接返回"无法生成代码"。
// 4. 代码风格应简洁、符合规范，直接针对用户需求。`
              },
              {
                role: 'user',
                content: `${message}\n\n相关代码上下文：\n${codeContext}`
              }
            ],
            stream: true
          })
        });

        const reader = response.body.getReader();
        const decoder = new TextDecoder();
        let buffer = '';
        let lastMessageIndex = this.chatMessages.length - 1;

        while (true) {
          const {done, value} = await reader.read();
          if (done) break;

          const chunk = decoder.decode(value, {stream: true});
          buffer += chunk;

          const lines = buffer.split('\n');
          buffer = lines.pop() || ''; // 保留不完整的行

          for (const line of lines) {
            const trimmedLine = line.trim();
            if (!trimmedLine) continue;

            // 处理流结束信号
            if (trimmedLine === 'data: [DONE]') {
              console.log('流式传输已完成');
              continue;
            }

            if (trimmedLine.startsWith('data: ')) {
              const jsonStr = trimmedLine.substring(6);

              try {
                const data = JSON.parse(jsonStr);

                // 处理包含内容的数据块
                if (data.choices &&
                    data.choices[0] &&
                    data.choices[0].delta &&
                    data.choices[0].delta.content !== undefined) {

                  this.chatMessages[lastMessageIndex].content += data.choices[0].delta.content;

                  this.$forceUpdate();
                  this.$nextTick(() => {
                    this.scrollToBottom();
                    this.highlightCodeBlocks(); // ← 新增：高亮所有代码块
                  });
                }

                // 处理使用量信息（最后一个数据块）
                if (data.usage) {
                  console.log('Token使用量:', data.usage);
                }

              } catch (parseError) {
                console.warn('JSON解析失败，跳过此行:', jsonStr, parseError);
                continue;
              }
            }
          }
        }
      } catch (error) {
        console.error('请求失败:', error);
        this.chatMessages[lastMessageIndex].content = '抱歉，请求过程中出现错误: ' + error.message;
      } finally {
        this.isStreaming = false;
        this.$forceUpdate();
        this.$nextTick(() => this.scrollToBottom());
      }
    },

    async executeSQL(sql) {
      if (this.language !== 'sql') {
        this.$message.warning('当前语言不是SQL');
        return;
      }

      try {
        const res = await request.post(`/code/execute-sql`, {query: sql});
        const result = res.data;

        // 判断是否成功
        if (result.code === 200 && Array.isArray(result.rows)) {
          const columns = result.columns || [];
          const rows = result.rows || [];

          if (rows.length === 0) {
            this.chatMessages.push({
              role: 'assistant',
              content: '查询成功，但未返回任何数据。',
              timestamp: new Date()
            });
          } else {
            // 统一处理列名：如果没有 columns，生成默认列名
            const displayColumns = columns.length > 0
                ? columns
                : Array.from({ length: rows[0]?.length || 0 }, (_, i) => `col${i + 1}`);

            // 构建表头
            const header = `| ${displayColumns.join(' | ')} |`;
            const separator = `|${displayColumns.map(() => '---').join('|')}|`;

            // 构建每一行，确保对齐并转义
            const rowLines = rows.map(row => {
              const alignedRow = [];
              for (let i = 0; i < displayColumns.length; i++) {
                const cell = row?.[i] != null
                    ? String(row[i])
                        .replace(/\|/g, '\\|')
                        .replace(/\n/g, '<br>') // 或 .replace(/\n/g, ' ')
                    : '';
                alignedRow.push(cell);
              }
              return `| ${alignedRow.join(' | ')} |`;
            });

            const tableMarkdown = [header, separator, ...rowLines].join('\n');
            const message = columns.length > 0
                ? `查询结果：\n\n${tableMarkdown}`
                : `查询结果（无列名）：\n\n${tableMarkdown}`;

            this.chatMessages.push({
              role: 'assistant',
              content: message,
              timestamp: new Date()
            });
          }
        } else {
          // 执行失败或非预期结构
          this.chatMessages.push({
            role: 'assistant',
            content: `执行结果：${result.message || '未知错误'}`,
            timestamp: new Date()
          });
        }
      } catch (err) {
        console.error('SQL 执行错误:', err.response.data.error);
        const errorMsg = err.response?.data?.error || err.message || '网络或服务器错误';
        this.$message.error('执行失败：' + errorMsg);
        this.chatMessages.push({
          role: 'assistant',
          content: `执行失败：${errorMsg}`,
          timestamp: new Date()
        });
      } finally {
        this.$nextTick(() => {
          this.scrollToBottom();
          this.highlightCodeBlocks(); // 虽然表格不是代码块，但确保其他内容高亮
        });
      }
    },
    removeUploadedFile(index) {
      const removedFile = this.uploadedFiles.splice(index, 1)[0];

      // 同时清理聊天记录中相关的消息
      this.chatMessages = this.chatMessages.filter(msg =>
          !msg.content.includes(`上传了文件 "${removedFile.name}"`) &&
          !msg.content.includes(`请分析以下文件内容：${removedFile.name}`)
      );

      this.$message.success(`已删除文件: ${removedFile.name}`);
    },
    createNewFile() {
      const now = new Date();
      const newFileIndex = this.fileList.length - 1; // 插入到“新建文件”按钮之前
      const timestamp =
          String(now.getHours()).padStart(2, '0') +
          String(now.getMinutes()).padStart(2, '0') +
          String(now.getSeconds()).padStart(2, '0');

      const newFile = {
        label: `SQL${timestamp}.sql`,
        content: '-- 新建的SQL文件\n'
      };

      // 插入到列表中（在“新建文件”按钮之前）
      this.fileList.splice(newFileIndex, 0, newFile);

      // 自动选中新文件
      this.selectFile(newFileIndex);
    },

    selectFile(index) {
      this.selectedFileIndex = index;
      const file = this.fileList[index];

      // 更新编辑器内容
      if (this.editor) {
        this.editor.setValue(file.content);
      }

      // 可选：根据文件类型切换语言
      const language = this.guessLanguage(file.label); // 如 .sql -> sql
      monaco.editor.setModelLanguage(this.editor.getModel(), language);
    },

    // 根据文件名后缀猜测语言
    guessLanguage(filename) {
      if (filename.endsWith('.sql')) return 'sql';
      if (filename.endsWith('.js') || filename.endsWith('.ts')) return 'javascript';
      return 'plaintext';
    },
    // 处理发送消息
    handleSendMessage() {
      if (!this.userInput.trim() || this.isStreaming) return;

      const message = this.userInput.trim();
      this.userInput = '';

      // 获取当前编辑器内容作为上下文
      const codeContext = this.editor ? this.editor.getValue() : '';

      // this.streamChatResponsedify(message, codeContext);
      this.streamChatResponse(message, codeContext);
    },

    // 执行快捷操作
    executeQuickAction(action) {
      this.quickActions.forEach(a => (a.selected = false));
      // 设置当前选中
      action.selected = true;
      return

      const selectedCode = this.editor ?
          this.editor.getModel().getValueInRange(this.editor.getSelection()) : '';

      let prompt = action.prompt;
      if (selectedCode) {
        prompt = `${prompt}:\n\`\`\`${this.language}\n${selectedCode}\n\`\`\``;
      }

      this.userInput = prompt;
      this.handleSendMessage();
    },

    // 插入代码到编辑器
    insertToEditor(con) {
      if (!this.editor || this.chatMessages.length === 0) return;
      if (con) {
        const currentPosition = this.editor.getPosition();
        const range = new monaco.Range(
            currentPosition.lineNumber,
            currentPosition.column,
            currentPosition.lineNumber,
            currentPosition.column
        );
        this.editor.executeEdits('copilot', [{
          range: range,
          // text: 'console.log("1111")'
          text: con
        }]);
      } else {
        const lastAssistantMessage = this.chatMessages
            .filter(msg => msg.role === 'assistant')
            .pop();

        if (lastAssistantMessage && lastAssistantMessage.content) {
          const currentPosition = this.editor.getPosition();
          const range = new monaco.Range(
              currentPosition.lineNumber,
              currentPosition.column,
              currentPosition.lineNumber,
              currentPosition.column
          );

          this.editor.executeEdits('copilot', [{
            range: range,
            // text: 'console.log("1111")'
            text: lastAssistantMessage.content
          }]);
        }
      }
      // 获取最后一条助手消息


      // this.copilotVisible = false;
    },

    // 清空聊天记录
    clearChat() {
      this.chatMessages = [];
    },


    // 格式化时间显示
    formatTime(timestamp) {
      if (!timestamp) return '';

      const date = new Date(timestamp);
      return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
    },

    // 更新最后一条助手消息（流式响应时使用）
    updateLastAssistantMessage(content) {
      const assistantMessages = this.chatMessages.filter(msg => msg.role === 'assistant');
      if (assistantMessages.length > 0) {
        const lastMessage = assistantMessages[assistantMessages.length - 1];
        lastMessage.content = content;

        // 强制更新视图
        this.$forceUpdate();

        // 滚动到底部
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }
    },

    // 滚动消息容器到底部
    scrollToBottom() {
      const container = this.$refs.messagesContainer;
      if (container) {
        container.scrollTop = container.scrollHeight;
      }
    },

    // 聚焦聊天输入框
    focusChatInput() {
      if (this.$refs.chatInput) {
        this.$refs.chatInput.focus();
      }
    },
// 方法：获取 AI 内联补全建议（只返回补全部分）
    async getAISuggestions(beforeCursor, afterCursor, language) {
      try {
        // 截取前文，避免过长（最多 50 行）
        const lines = beforeCursor.split('\n');
        const contextLines = lines.slice(-50).join('\n'); // 只取最后 50 行

        const prompt = `你是一个代码补全助手。请根据上下文，预测光标处接下来最可能输入的代码片段（只返回补全部分，不要重复前面的内容，不要解释）。

语言：${language}

当前光标前代码：
\`\`\`${language}
${contextLines}
\`\`\`

请直接输出补全部分（从光标位置开始）：
`;

        const response = await fetch('https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions', {
          method: 'POST',
          headers: {
            'Authorization': 'Bearer sk-a731f551ecd34cdbb06487f7464ff978',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            model: 'qwen-plus',
            messages: [
              {
                role: 'user',
                content: prompt
              }
            ],
            max_tokens: 64,  // 控制补全长度
            temperature: 0.2, // 更确定性
            top_p: 0.9
          })
        });

        const data = await response.json();

        if (data.choices && data.choices[0]?.message?.content) {
          let completion = data.choices[0].message.content;

          // 清理：去除可能的多余空格、换行
          completion = completion.replace(/^\s+/, '').replace(/\s+$/, '');

          // 避免返回完整函数定义，只取“补全部分”
          return [{text: completion}];
        }

        return [];
      } catch (error) {
        console.error('AI 补全请求失败:', error);
        return [];
      }
    },

// 方法：设置 Copilot 内联补全（已修复）
    setupCopilotCompletions() {
      const provider = monaco.languages.registerInlineCompletionsProvider(this.language, {
        provideInlineCompletions: async (model, position, context, token) => {
          clearTimeout(this.copilotTimer);

          return new Promise((resolve) => {
            this.copilotTimer = setTimeout(async () => {
              try {
                const codeBeforeCursor = model.getValueInRange({
                  startLineNumber: 1,
                  startColumn: 1,
                  endLineNumber: position.lineNumber,
                  endColumn: position.column,
                });

                const codeAfterCursor = model.getValueInRange({
                  startLineNumber: position.lineNumber,
                  startColumn: position.column,
                  endLineNumber: model.getLineCount(),
                  endColumn: model.getLineMaxColumn(model.getLineCount()),
                });

                if (codeAfterCursor && !/^\s*$/.test(codeAfterCursor)) {
                  resolve({items: []});
                  return;
                }

                if (!codeBeforeCursor.trim()) {
                  resolve({items: []});
                  return;
                }

                const suggestions = await this.getAISuggestionsbq(
                    codeBeforeCursor,
                    codeAfterCursor,
                    this.language
                );

                // 🔴 关键修复：严格检查 suggestions[0].text 是否为有效字符串
                if (!suggestions || suggestions.length === 0) {
                  resolve({items: []});
                  return;
                }

                const suggestion = suggestions[0];
                const insertText = suggestion.text;

                // 🔴 必须确保 insertText 是非空字符串
                if (!insertText || typeof insertText !== 'string' || insertText.trim() === '') {
                  resolve({items: []});
                  return;
                }

                const range = {
                  startLineNumber: position.lineNumber,
                  startColumn: position.column,
                  endLineNumber: position.lineNumber,
                  endColumn: position.column,
                };

                resolve({
                  items: [
                    {
                      insertText: insertText, // ✅ 确保是字符串
                      range: range,
                      // command: {
                      //   id: 'editor.action.inlineSuggest.commit',
                      //   title: 'Accept Inline Suggestion'
                      // }
                    }
                  ]
                });

              } catch (error) {
                console.error('内联补全失败:', error);
                resolve({items: []}); // 🔴 出错时返回空数组，不要抛出
              }
            }, 300);
          });
        },
        freeInlineCompletions: (completions) => {
          // 清理资源
          console.log('释放内联补全资源', completions);
        },

        handleItemDidShow: (completions, item) => {
          // 可用于埋点统计
          console.log('展示内联补全项', item);
        }
      });

      // 保存 provider 引用，便于销毁
      this.$once('hook:beforeDestroy', () => {
        if (provider && provider.dispose) {
          provider.dispose();
        }
      });
    },

    async handleFileUpload(upload) {
      const file = upload.file;
      const reader = new FileReader();

      return new Promise((resolve, reject) => {
        reader.onload = (e) => {
          const content = e.target.result;

          // 保存文件信息（含内容）
          this.uploadedFiles.push({
            name: file.name,
            size: file.size,
            content: content,
            language: this.guessLanguage(file.name)
          });

          resolve(); // 完成上传流程
        };

        reader.onerror = () => {
          this.$message.error(`读取文件失败: ${file.name}`);
          reject();
        };

        reader.readAsText(file); // 以文本方式读取
      });
    },

    async getAISuggestionsbq(beforeCursor, afterCursor, language) {
      try {
        const lines = beforeCursor.split('\n');
        const contextLines = lines.slice(-50).join('\n');

        const prompt = `你是一个代码补全助手。请根据上下文，预测光标处接下来最可能输入的代码片段（只返回补全部分，不要重复前面的内容，不要解释）。

语言：${language}

当前光标前代码：
\`\`\`${language}
${contextLines}
\`\`\`

请直接输出补全部分（从光标位置开始）：
`;

        const response = await fetch('https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions', {
          method: 'POST',
          headers: {
            'Authorization': 'Bearer sk-a731f551ecd34cdbb06487f7464ff978',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            model: 'qwen-plus',
            messages: [{role: 'user', content: prompt}],
            max_tokens: 64,
            temperature: 0.2,
            top_p: 0.9
          })
        });

        const data = await response.json();

        if (data.choices && data.choices[0]?.message?.content) {
          let completion = data.choices[0].message.content;

          // 🔴 清理：确保是字符串，且非空
          completion = completion?.trim(); // 防止 null/undefined

          if (completion && typeof completion === 'string') {
            return [{text: completion}];
          }
        }

        return []; // 🔴 任何情况下都返回数组
      } catch (error) {
        console.error('AI 补全请求失败:', error);
        return []; // 🔴 出错也返回空数组
      }
    },
    // 流式聊天响应

    async streamChatResponsedify(message, codeContext) {
      this.isStreaming = true;
      this.chatMessages.push({
        role: 'user',
        content: message,
        timestamp: new Date()
      });

      // 添加助手消息占位符用于流式更新
      this.chatMessages.push({
        role: 'assistant',
        content: '',
        timestamp: new Date()
      });

      const lastMessageIndex = this.chatMessages.length - 1;

      try {
        const response = await fetch('https://api.dify.ai/v1/chat-messages', {
          method: 'POST',
          headers: {
            'Authorization': 'Bearer app-KSa4rzNOXcTjIU0b60PMdAPu', // 替换为你的 Dify App API Key
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            inputs: {}, // 如果你在 Dify 后台定义了变量（如 code_context），可传入
            query: `${message}\n\n相关代码上下文：\n${codeContext}`,
            response_mode: 'streaming',
            conversation_id: '', // 若需继续对话，填入之前的 conversation_id
            user: 'Lillen', // 用户标识，可用于追踪
            files: []
          })
        });

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        const reader = response.body.getReader();
        const decoder = new TextDecoder();
        let buffer = '';

        while (true) {
          const {done, value} = await reader.read();
          if (done) break;

          const chunk = decoder.decode(value, {stream: true});
          buffer += chunk;

          const lines = buffer.split('\n');
          buffer = lines.pop() || ''; // 保留不完整的最后一行

          for (const line of lines) {
            const trimmedLine = line.trim();
            if (!trimmedLine || !trimmedLine.startsWith('data: ')) continue;

            const dataStr = trimmedLine.substring(6).trim();
            if (dataStr === '[DONE]') {
              console.log('Dify 流式传输完成');
              continue;
            }

            try {
              const data = JSON.parse(dataStr);

              // Dify 的流式响应中，增量内容在 `answer` 字段
              if (data.answer !== undefined) {
                this.chatMessages[lastMessageIndex].content += data.answer;
                this.$forceUpdate();
                this.$nextTick(() => this.scrollToBottom());
              }

              // 可选：处理 conversation_id（用于后续对话）
              if (data.conversation_id) {
                // 你可以保存到组件 data 中，用于下一次请求
                this.currentConversationId = data.conversation_id;
              }

            } catch (parseError) {
              console.warn('Dify 响应解析失败:', dataStr, parseError);
            }
          }
        }
      } catch (error) {
        console.error('Dify 请求失败:', error);
        this.chatMessages[lastMessageIndex].content = '抱歉，请求过程中出现错误: ' + error.message;
      } finally {
        this.isStreaming = false;
        this.$forceUpdate();
        this.$nextTick(() => this.scrollToBottom());
      }
    },

    setupCustomCompletions() {
      monaco.languages.registerCompletionItemProvider('javascript', {
        provideCompletionItems: (model, position) => {
          const suggestions = [
            {
              label: 'console.log',
              kind: monaco.languages.CompletionItemKind.Function,
              documentation: '输出日志到控制台',
              insertText: 'console.log(${1:value});',
              insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
            },
            {
              label: 'setTimeout',
              kind: monaco.languages.CompletionItemKind.Function,
              documentation: '设置定时器',
              insertText: 'setTimeout(() => {\n\t${1:// code}\n}, ${2:delay});',
              insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
            }
          ];
          return {suggestions};
        },
        triggerCharacters: ['.', '('] // 触发补全的字符
      });
    },

    saveCurrentFile() {
      if (this.editor && this.selectedFileIndex !== -1) {
        const currentContent = this.editor.getValue();
        console.log(this.fileList[this.selectedFileIndex]);
        this.fileList[this.selectedFileIndex].content = currentContent;
        if (this.fileList[this.selectedFileIndex].id) {
          request.put(`/code-files/${this.fileList[this.selectedFileIndex].id}`, {
            "label": this.fileList[this.selectedFileIndex].label,
            "content": currentContent
          }).then(res => {
            console.log('res.data', res.data)
            this.$message.success('文件已修改');
          })
        } else {
          request.post('/code-files', {
            "label": this.fileList[this.selectedFileIndex].label,
            "content": currentContent
          }).then(res => {
            console.log('res.data', res.data)
            this.$message.success('文件已保存');
          })
        }

      }
    },

    deleteCurrentFile() {
      if (this.editor && this.selectedFileIndex !== -1) {
        if (this.fileList[this.selectedFileIndex].id) {
          request.delete(`/code-files/${this.fileList[this.selectedFileIndex].id}`).then(res => {
            console.log('res.data', res.data)
            this.fileList.splice(this.selectedFileIndex, 1);
            this.$message.success('文件已删除');
          })
        } else {
          this.fileList.splice(this.selectedFileIndex, 1);
          this.$message.success('文件已删除');
        }

      }
    },
    // ✅ 新增：执行SQL
    initMonaco() {
      // ✅ 1. 注册语言 ID
      monaco.languages.register({id: 'sql'});
      monaco.languages.setLanguageConfiguration('sql', sqlcode.conf);
      monaco.languages.setMonarchTokensProvider('sql', sqlcode.language);
      // 创建编辑器实例

      this.editor = monaco.editor.create(this.$refs.monacoContainer, {
        value: '',
        language: this.language,
        theme: 'vs',
        automaticLayout: true, // 自动调整布局，非常重要
        scrollBeyondLastLine: false,
        minimap: {enabled: false}, // 可选关闭小地图
        fontSize: 14,
        lineNumbers: 'on',
        roundedSelection: true,
        scrollbar: {
          useShadows: false,
        },
        readOnly: this.readOnly,
        // 启用代码补全等智能功能
        suggestOnTriggerCharacters: true,
        quickSuggestions: true,
        wordBasedSuggestions: true,

      });

      // ✅ 关键：初始化后立即加载当前选中文件的内容


      // 监听内容变化，向父组件传递值
      this.editor.onDidChangeModelContent(() => {
        const value = this.editor.getValue();
        this.$emit('input', value);
        this.$emit('change', value);
      });

      // 可选：监听失焦事件
      this.editor.onDidBlurEditorText(() => {
        this.$emit('blur');
      });

      // 监听内容变化
      this.editor.onDidChangeModelContent(() => {
        const value = this.editor.getValue();
        this.$emit('input', value);
        this.$emit('change', value);

        // 可选：同步回当前文件（实现编辑保存）
        // this.fileList[this.selectedFileIndex].content = value;
      });
      // // ✅ 4. 创建编辑器
      // this.editor = monaco.editor.create(this.$refs.monacoContainer, {
      //   value: this.value,
      //   language: 'sql', // 必须是 'sql'
      //   theme: this.theme,
      //   automaticLayout: true,
      //   scrollBeyondLastLine: false,
      //   minimap: { enabled: false },
      //   fontSize: 14,
      //   lineNumbers: 'on',
      //   readOnly: this.readOnly,
      // });
      this.setupCustomCompletions();
      this.setupCopilotCompletions();
    },
    // 提供格式化代码的方法（注意需要延迟执行）
    formatCode() {
      setTimeout(() => {
        this.editor.getAction('editor.action.formatDocument').run();
      }, 300);
    },

    switchToLoadingCursor() {
      const cursorLayer = document.querySelector('.cursors-layer');
      if (cursorLayer && !this.loadingCursor) {
        this.loadingCursor = document.createElement('div');
        this.loadingCursor.className = 'copilot-loading-cursor';
        this.loadingCursor.innerHTML = '<div class="loading-spinner"></div>';
        cursorLayer.appendChild(this.loadingCursor);
      }
    },

    switchToDefaultCursor() {
      if (this.loadingCursor) {
        this.loadingCursor.remove();
        this.loadingCursor = null;
      }
    },
    // 更新编辑器内容（防止循环更新）
    updateEditorValue(newValue) {
      if (this.editor && newValue !== this.editor.getValue()) {
        this.editor.setValue(newValue);
      }
    }
  },

  watch: {
    value(newVal) {
      this.updateEditorValue(newVal);
    },
    language(newLang) {
      if (this.editor) {
        monaco.editor.setModelLanguage(this.editor.getModel(), newLang);
      }
    },
    theme(newTheme) {
      if (this.editor) {
        monaco.editor.setTheme(newTheme);
      }
    }
  }
};
</script>

<style scoped>
/* 新建文件按钮样式 */
.btn-new-file {
  width: 90%;
  margin: 8px auto;
  display: block;
  font-size: 13px !important;
  font-weight: 500;
  color: #1890ff !important; /* 蓝色文字 */
  border-color: #1890ff;
  background-color: #e6f7ff !important;
  border-radius: 6px;
  transition: all 0.2s ease;
}

.btn-new-file:hover {
  background-color: #bae7ff !important;
  color: #fff !important;
  border-color: #1890ff;
  transform: translateY(-1px);
}

.list-container {
  background-color: #f8f9fa;
  border-right: 1px solid #ddd;
  padding: 10px 0;
  overflow-y: auto;
}

.file-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.file-item {
  padding: 8px 12px;
  cursor: pointer;
  font-size: 13px;
  color: #333;
  border-left: 3px solid transparent;
  transition: all 0.2s;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.file-item:hover {
  background-color: #e9ecef;
}

.file-item.active {
  background-color: #e0f2ff;
  color: #007acc;
  font-weight: 500;
  border-left-color: #007acc;
}

.editor-layout {
  width: 100%;
  border: 1px solid #ddd;
  border-radius: 6px;
  overflow: hidden;
  display: flex;
  height: 100%;
}

.editor-container {
  height: 100%;
  border-right: 1px solid #ddd;
}

.monaco-editor-container {
  width: 100%;
  height: 100%;
}

.chat-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  background-color: #fff;
  border-left: 1px solid #eaeaea;
}

.chat-wrapper {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 10px;
  overflow: hidden;
  background-color: #f5f7f9;
}

.chat-header {
  padding-bottom: 10px;
  border-bottom: 1px solid #a0a8b9;
  font-weight: 600;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 10px 0;

}

.message {
  display: flex;
  margin-bottom: 12px;
  align-items: flex-start;
}

.message.user {
  flex-direction: row-reverse;
}

.message-avatar {
  margin: 0 8px;
}

.message-content {
  max-width: 80%;
  padding: 8px 12px;
  border-radius: 12px;
  font-size: 14px;
  line-height: 1.5;
}

.message.user .message-content {
  background-color: rgb(209 233 255 / 50%);
  color: #101828;
}

.message.assistant .message-content {
  background-color: #fff;
  color: #101828;
}

.quick-actions {
  padding: 8px 0;
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  border-top: 1px solid #e4e7ed;
  border-bottom: 1px solid #e4e7ed;
}

.chat-input-container {
  padding: 8px 0;
  border-top: 1px solid #e4e7ed;
}

.dialog-footer {
  padding-top: 8px;
  border-top: 1px solid #e4e7ed;
  text-align: right;
  font-size: 12px;
}

.typing-indicator {
  display: flex;
  align-items: center;
}

.typing-indicator span {
  width: 6px;
  height: 6px;
  background: #999;
  border-radius: 50%;
  display: inline-block;
  margin: 0 2px;
  animation: typing 1.4s infinite;
}

@keyframes typing {
  0%, 60%, 100% {
    opacity: 0.3;
  }
  30% {
    opacity: 1;
  }
}

.message-time {
  color: darkgrey;
  font-size: 11px;
}

/* 支持代码块高亮 */
.message-text pre {
  background: #f5f5f5;
  padding: 10px;
  border-radius: 6px;
  overflow-x: auto;
  margin: 8px 0;
  font-family: 'Courier New', monospace;
  font-size: 13px;
}

.message-text code {
  font-family: 'Courier New', monospace;
  background: #f0f0f0;
  padding: 2px 4px;
  border-radius: 4px;
}

.quick-actions .el-button.is-selected {
  color: #409EFF;
  border-color: #c6e2ff;
  background-color: #ecf5ff;
}
</style>
<style>

.file-manager-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 16px;
  border-bottom: 1px solid #ebeef5;
  background-color: #f5f7fa;
}

.file-manager-title {
  font-size: 16px;
  font-weight: bold;
  color: #303133;
}

.btn-new-file-icon {
  padding: 6px;
  font-size: 12px;
  color: #606266;
}

.btn-new-file-icon:hover {
  color: #409eff;
}

.code-container {
  margin: 10px 0;
}

.code-header {
  background-color: #f1f3f5;
  padding: 4px 10px;
  font-size: 12px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #e0e0e0;
}

.copy-button {
  padding: 2px 8px;
  background: #6c757d;
  color: white;
  border: none;
  border-radius: 3px;
  cursor: pointer;
  font-size: 12px;
}

.copy-button:hover {
  opacity: 0.9;
}

.chat-messages table {
  width: 100%;
  border-collapse: collapse;
  margin: 10px 0;
  font-size: 13px;
  overflow: hidden;
  border-radius: 4px;
}

.chat-messages th,
.chat-messages td {
  border: 1px solid #e0e0e0;
  padding: 8px 10px;
  text-align: left;
  word-break: break-word;
}

.chat-messages th {
  background-color: #f8f9fa;
  font-weight: 600;
  color: #333;
}
.editor-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background-color: #f5f7fa;
  border-bottom: 1px solid #ebeef5;
  font-weight: bold;
  font-size: 14px;
}

.editor-title {
  color: #303133;
}
</style>